using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HollowOut : Image
{
    private float radius = 40f;
    private int triangleNum = 10;
    private RectTransform highArea;  // 镂空区域
    private RectTransform outer_trans;  // 背景区域
    private Vector2 inner_rt;           // 镂空区域的右上角坐标
    private Vector2 inner_lb;           // 镂空区域的左下角坐标
    private Vector2 outer_rt;           // 背景区域的右上角坐标
    private Vector2 outer_lb;           // 背景区域的左下角坐标
    private RectTransform clickArea;    // 可点击区域
    private bool m_AnimComplate = true; // 高亮（镂空）区域是否变化完毕

    /// <summary>是否显示镂空区域</summary>
    public bool ShowHollowOut { get; set; }

    protected override void Awake()
    {
        outer_trans = GetComponent<RectTransform>();

        //计算边界
        CalcBounds();
        //刷新
        SetAllDirty();

        ShowHollowOut = true;
    }

    public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        // 点击穿透镂空区域，默认是没有穿透的
        // 思路：判断当前鼠标点击的屏幕点是否包含在镂空区域，是则可以穿透下去，否则不可穿透
        if (!clickArea) return true;
        bool result = !RectTransformUtility.RectangleContainsScreenPoint(clickArea, sp, eventCamera);
        return result;
    }

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        float tw = Mathf.Abs(inner_lb.x - inner_rt.x);//图片的宽
        float th = Mathf.Abs(inner_lb.y - inner_rt.y);//图片的高
        float twr = tw / 2;
        float thr = th / 2;

        if (this.radius < 0)
            this.radius = 0;
        float radius = tw / this.radius;//半径这里需要动态计算确保不会被拉伸
        if (radius > twr)
            radius = twr;
        if (radius < 0)
            radius = 0;
        if (triangleNum <= 0)
            triangleNum = 1;

        UIVertex vert = UIVertex.simpleVert;
        vert.color = color;

        #region 绘制镂空后的整个Mask背景
        //0 outer左下角
        vert.position = new Vector2(outer_lb.x, outer_lb.y);
        vh.AddVert(vert);
        //1 outer左上角
        vert.position = new Vector2(outer_lb.x, outer_rt.y);
        vh.AddVert(vert);
        //2 outer右上角
        vert.position = new Vector2(outer_rt.x, outer_rt.y);
        vh.AddVert(vert);
        //3 outer右下角
        vert.position = new Vector2(outer_rt.x, outer_lb.y);
        vh.AddVert(vert);

        //4 inner左下角
        vert.position = new Vector3(inner_lb.x, inner_lb.y);
        vh.AddVert(vert);
        //5 inner左上角
        vert.position = new Vector3(inner_lb.x, inner_rt.y);
        vh.AddVert(vert);
        //6 inner右上角
        vert.position = new Vector3(inner_rt.x, inner_rt.y);
        vh.AddVert(vert);
        //7 inner右下角
        vert.position = new Vector3(inner_rt.x, inner_lb.y);
        vh.AddVert(vert);

        //不显示镂空
        if (ShowHollowOut == false)
        {
            vh.AddTriangle(0, 1, 2);
            vh.AddTriangle(2, 3, 0);
            return;
        }

        //绘制三角形
        vh.AddTriangle(4, 0, 1);
        vh.AddTriangle(4, 1, 5);
        vh.AddTriangle(5, 1, 2);
        vh.AddTriangle(5, 2, 6);
        vh.AddTriangle(6, 2, 3);
        vh.AddTriangle(6, 3, 7);
        vh.AddTriangle(7, 3, 0);
        vh.AddTriangle(7, 0, 4);
        #endregion

        #region 处理镂空区域的边界（变得平滑）
        //内四边形顶点
        List<Vector2> commonPointOutside = new List<Vector2>();//共点列表 
        Vector2 point1 = new Vector2(inner_lb.x, inner_lb.y);//左下共点
        Vector2 point2 = new Vector2(inner_lb.x, inner_lb.y + radius);//决定首次旋转方向的点
        commonPointOutside.Add(point1);
        commonPointOutside.Add(point2);
        point1 = new Vector2(inner_lb.x, inner_rt.y);//左上共点
        point2 = new Vector2(inner_lb.x + radius, inner_rt.y);
        commonPointOutside.Add(point1);
        commonPointOutside.Add(point2);
        point1 = new Vector2(inner_rt.x, inner_rt.y);//右上共点
        point2 = new Vector2(inner_rt.x, inner_rt.y - radius);
        commonPointOutside.Add(point1);
        commonPointOutside.Add(point2);
        point1 = new Vector2(inner_rt.x, inner_lb.y);//右下共点
        point2 = new Vector2(inner_rt.x - radius, inner_lb.y);
        commonPointOutside.Add(point1);
        commonPointOutside.Add(point2);

        //圆心公共点
        List<Vector2> commonPoint = new List<Vector2>();//共点列表 
        point1 = new Vector2(inner_lb.x + radius, inner_lb.y + radius);//左下共点
        point2 = new Vector2(inner_lb.x, inner_lb.y + radius);//决定首次旋转方向的点
        commonPoint.Add(point1);
        commonPoint.Add(point2);
        point1 = new Vector2(inner_lb.x + radius, inner_rt.y - radius);//左上共点
        point2 = new Vector2(inner_lb.x + radius, inner_rt.y);
        commonPoint.Add(point1);
        commonPoint.Add(point2);
        point1 = new Vector2(inner_rt.x - radius, inner_rt.y - radius);//右上共点
        point2 = new Vector2(inner_rt.x, inner_rt.y - radius);
        commonPoint.Add(point1);
        commonPoint.Add(point2);
        point1 = new Vector2(inner_rt.x - radius, inner_lb.y + radius);//右下共点
        point2 = new Vector2(inner_rt.x - radius, inner_lb.y);
        commonPoint.Add(point1);
        commonPoint.Add(point2);

        Vector2 pos2;


        float degreeDelta = (float)(Mathf.PI / 2 / triangleNum);//每一份等腰三角形的角度 默认6份
        List<float> degreeDeltaList = new List<float>() { Mathf.PI, Mathf.PI / 2, 0, (float)3 / 2 * Mathf.PI };

        for (int j = 0; j < commonPoint.Count; j += 2)
        {
            float curDegree = degreeDeltaList[j / 2];//当前的角度
            AddVert(commonPointOutside[j], tw, th, vh, vert);//添加扇形区域所有三角形公共顶点//TODO :这里改成外面的点
            int thrdIndex = vh.currentVertCount;//当前三角形第二顶点索引
            int TriangleVertIndex = vh.currentVertCount - 1;//一个扇形保持不变的顶点索引
            List<Vector2> pos2List = new List<Vector2>();
            for (int i = 0; i < triangleNum; i++)
            {
                curDegree += degreeDelta;
                if (pos2List.Count == 0)
                {
                    AddVert(commonPoint[j + 1], tw, th, vh, vert);
                }
                else
                {
                    vert.position = pos2List[i - 1];
                    vert.uv0 = new Vector2(pos2List[i - 1].x + 0.5f, pos2List[i - 1].y + 0.5f);
                }
                pos2 = new Vector2(commonPoint[j].x + radius * Mathf.Cos(curDegree), commonPoint[j].y + radius * Mathf.Sin(curDegree));
                AddVert(pos2, tw, th, vh, vert);
                vh.AddTriangle(TriangleVertIndex, thrdIndex, thrdIndex + 1);
                thrdIndex++;
                pos2List.Add(vert.position);
            }
        }
        #endregion
    }

    private Vector2[] GetTextureUVS(Vector2[] vhs, float tw, float th)
    {
        int count = vhs.Length;
        Vector2[] uvs = new Vector2[count];
        for (int i = 0; i < uvs.Length; i++)
        {
            uvs[i] = new Vector2(vhs[i].x / tw + 0.5f, vhs[i].y / th + 0.5f);//矩形的uv坐标  因为uv坐标原点在左下角，vh坐标原点在中心 所以这里加0.5（uv取值范围0~1）
        }
        return uvs;
    }

    private void AddVert(Vector2 pos0, float tw, float th, VertexHelper vh, UIVertex vert)
    {
        vert.position = pos0;
        vert.uv0 = GetTextureUVS(new[] { new Vector2(pos0.x, pos0.y) }, tw, th)[0];
        vh.AddVert(vert);
    }

    /// <summary>
    /// 计算边界
    /// </summary>
    private void CalcBounds()
    {
        Bounds bounds;
        if (highArea != null)
        {
            bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(outer_trans, highArea);
            inner_rt = bounds.max;
            inner_lb = bounds.min;
        }
        else
        {
            inner_rt = Vector2.zero;
            inner_lb = Vector2.zero;
        }
        outer_rt = outer_trans.rect.max;
        outer_lb = outer_trans.rect.min;
    }

    /// <summary>设置需要高亮的矩形区域</summary>
    public void UpdateHighArea(RectTransform highArea)
    {
        m_AnimComplate = true;
        this.highArea = highArea;
        Refresh();
    }

    /// <summary>设置需要高亮的矩形区域，动画版</summary>
    public void UpdateHighArea(RectTransform highArea, Action complate)
    {
        m_AnimComplate = false;
        bool isFist = this.highArea == null;
        this.highArea = highArea;
        //LogManager.Log($"进入，isFirst:{isFist}", nameof(HollowOut));
        if (isFist || !this.highArea)
        {
            Refresh();
            complate?.Invoke();
            m_AnimComplate = true;
        }
        else
            StartCoroutine(RefreshAnim(complate));
    }

    /// <summary>更新需要点击的区域</summary>
    public void UpdateClickArea(RectTransform clickArea)
    {
        this.clickArea = clickArea;
    }

    public void Refresh()
    {
        //计算边界
        CalcBounds();
        //刷新
        SetAllDirty();
    }

    private IEnumerator RefreshAnim(Action complate)
    {
        var bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(outer_trans, highArea);

        // 目标位置
        Vector2 tar_inner_rt = bounds.max;
        Vector2 tar_inner_lb = bounds.min;

        // 计算两个点的移动距离
        float distance_rt = Vector2.Distance(inner_rt, tar_inner_rt);
        float distance_lb = Vector2.Distance(inner_lb, tar_inner_lb);

        // 取最大距离，确保两个点同步完成
        float maxDistance = Mathf.Max(distance_rt, distance_lb);

        // 设定最短和最长时间（0.25秒至4秒）
        //float minTime = 0.25f;
        //float maxTime = 2f;

        // 计算动画持续时间，范围在[0.25,2]
        //float totalTime = Mathf.Lerp(minTime, maxTime, Mathf.Clamp01(maxDistance / Screen.width));
        float totalTime = .5f;
        float elapsedTime = 0f;

        // 记录初始位置
        Vector2 start_rt = inner_rt;
        Vector2 start_lb = inner_lb;

        while (elapsedTime < totalTime)
        {
            elapsedTime += Time.deltaTime;
            float t = Mathf.Clamp01(elapsedTime / totalTime); // 归一化时间 0~1

            // 使用 Lerp 确保两者同步完成
            inner_rt = Vector2.Lerp(start_rt, tar_inner_rt, t);
            inner_lb = Vector2.Lerp(start_lb, tar_inner_lb, t);

            SetAllDirty();
            yield return null;
        }

        // 确保最终对齐
        inner_rt = tar_inner_rt;
        inner_lb = tar_inner_lb;

        SetAllDirty();
        complate?.Invoke();
        m_AnimComplate = true;
    }

    /// <summary>高亮（镂空）区域是否变化完毕</summary>
    public bool AnimComplate => m_AnimComplate;
}